home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
msdos
/
raytrace
/
pov
/
gen
/
povclk
/
envunit.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1979-12-31
|
23KB
|
865 lines
unit EnvUnit; { Version 2.8 88/11/07
Handy little routines to simplify using the environment string.
See the example program ENVTEST.PAS, for hints on how to use this unit.
MOST LIKELY TO BE USED: 1) FFind - search the path for a named file and
return the fully qualified file name
if it is found.
2) PathTo - search the path for a named file;
return the path to that file if found
3) ParamStr - the complete parameter string
This program is hereby donated to the public domain. It may be freely copied,
used & modified without charge or fee.
Author : Mike Babulic
3827 Charleswood Dr. N.W.
Calgary, Alberta
CANADA
T2L 2C7
Compuserve ID : 72307,314
Modification Log:
-----------------
88/11/07 - Version 2.8 - EnvStrPtr changed so root environment could be
found in DOS 2.0-3.2. Offset $2C from the root PSP is 0000 in
these early DOS's, so an alternative method of finding the
envirinment must be used. (see Dr Dobb's Journal, Dec.88, p.57)
}
interface
uses Dos;
{$IFDEF VER40} {These objects are already in TP Version 5's Dos Unit}
{I've included them so you can upgrade gracefully}
type
PathStr = string[79];
DirStr = string[67];
NameStr = string[8];
ExtStr = string[4];
function DosVersion: word; { lo = version (ex. 3); hi = fraction (ex. .2) }
function EnvCount: integer; {number of Environment Strings}
function EnvStr(Index:integer): string; {get Env. String number index}
function GetEnv(EnvVar:string): string; {get Env. String named by EnvVar}
function FExpand(Path:PathStr):PathStr;
{expand the path to a fully qualified file name}
function FSearch(Path:PathStr;DirList:string):PathStr;
{Search DirList (paths separated by ";") for Path & return full name of
this file}
procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
{$ENDIF}
var MyPath : string; {Path & Name of the running program}
MyDir : DirStr;
MyName : NameStr;
MyExt : ExtStr;
function DOS_Version: integer;
{Returns the version of DOS being used (ex. 302 is DOS 3.2)}
function ParamString: String;
{Returns the complete parameter string}
function EnvStrPtr:Pointer;
{Point to environment strings}
function EnvSize:LongInt;
{Size of the current environment in bytes}
function MaxEnvSize:LongInt;
{Maximum size of the current environment in bytes}
var PSP : word; {Program Segment Prefix; initially = PrefixSeg}
function ProgPath: PathStr; {Path to program owning current PSP}
function ProgDir: DirStr; {Directory of program owning current PSP}
function ProgName: NameStr; {Name of program owning current PSP}
function ProgExt: ExtStr; {Extension of program owning current PSP}
procedure UseMyPSP;
{Use the program's PSP to find the environment}
procedure UseParentPSP;
{Use the parent of the current PSP to find the environment}
procedure UseRootPSP;
{Use the parent of the current PSP to find the environment}
procedure DelEnv(name:String);
{delete the named string from the current environment}
function SetEnv(name,env:String):boolean;
{set the named environment string to env}
function SetPath(path:String):boolean;
{set the environment "PATH=" string to path}
function FirstEnv:String;
{Get the First Environment string}
function NextEnv:String;
{Get the Next Environment string}
procedure SkipEnv;
{Skip the Next Environment string}
function EOEnv:Boolean;
{True if End Of Environment}
function GetEnvPtr(name:String):Pointer;
{return a pointer to the named environment variable's string}
function FirstNamed(name,delim:String):String;
{Get the first string in an the named environment specification
eg. If name = 'PATH' and delim = ';' then get the first path string
"Path" strings are delimited by semicolins: ";" }
function NextNamed:String;
{Get the next string in an environment specification}
function EONamed:Boolean;
{True if end of environment specification}
function FirstPath:String;
{Almost the same as Firstnamed('PATH',';'), but appends a '\' to the
string if needed}
function NextPath:String;
{File Utilities}
const AllowWildcards : boolean = TRUE;
{Used by FileExists and routines that depend on it (PathTo, FFind).
If TRUE these functions will allow wildcard characters in a file name}
function ContainsWildcards(filename:string):boolean;
{True if filename contains wildcard characters}
function PathTo(filename:string):string;
{Searches the environment PATH and returns a path to the named file.
Check the current directory,
then search the environment PATH,
then check the directory containing the calling program (MyDir).
If the file is still not found, return a null string ('')}
const FFindErr = '.';
function FFind(filename:string):string;
{Find the File called "filename".
Check the current directory,
then search the environment PATH,
then check the directory containing the calling program (MyDir).
- if "filename" is found return the fully qualified file name
of the filename.
- if "filename" is NOT found then return FFindErr.
- a period is returned because if you write something like:
Assign(aFile,FFind('MISSING.TXT'));
Reset(aFile);
and FFind returned '' when it failed then aFile would be assigned
to the standard INPUT file (usually the keyboard)! }
{misc}
function FileExists(name:string):Boolean; {True if named file exists}
procedure PtrInc(var p:Pointer; n: Longint); {Increment pointer by n}
function PtrDiff(p1,p2:Pointer):Longint; {p1-p2 in Bytes}
function UpperStr(s:string):string; {string to uppercase}
{----------------------------------------------------------------------------}
implementation
type pointr = record lo,hi: word end;
procedure PtrInc(var p:Pointer; n: Longint); {Increment pointer by n}
var
pt : pointr absolute p;
c : pointr absolute n;
begin
n := pt.lo + n;
pt.hi := (n AND $FFFF0000) shr 4 + pt.hi;
pt.lo := c.lo;
end;
function PtrDiff(p1,p2:pointer): LongInt;
var
a : pointr absolute p1;
b : pointr absolute p2;
begin
PtrDiff := (a.hi-b.hi) shl 4 + (a.lo-b.lo)
end;
function UpperStr(s:string):string; {string to uppercase}
var i : integer;
begin
for i := 1 to length(s) do
UpperStr[i] := upcase(s[i]);
Upperstr[0] := s[0];
end;
{-----------------------------------------------------------------------------}
type WordP = ^word;
MCB = packed record
kind : char; {is 'M' or 'Z'}
PID : word;
PCount : word; {# of paragraphs}
end;
MCBPtr = ^MCB;
function EnvSeg : word; {Segment containing the environment}
var
ESeg : word;
done,found : boolean;
begin
ESeg := WordP(Ptr(PSP,$2C))^;
if ESeg = 0 then begin {DOS 2.0-3.2 root zeros this pointer, so..}
ESeg := Pred(PSP); {hunt through the MCB chain for ESeg}
repeat
ESeg := ESeg + MCBPtr(Ptr(ESeg,0))^.PCount + 1;
with MCBPtr(Ptr(ESeg,0))^ do begin
found := (PID=PSP);
done := found {found it!}
or (PID<>0) {past command.com's storage}
or (kind='Z'); {end of the chain}
end;
until done;
Eseg := Succ(ESeg);
if not found then ESeg := 0;
end;
EnvSeg := ESeg;
end;
function EnvStrPtr:Pointer;
begin
EnvStrPtr := Ptr(EnvSeg,0);
end;
function EnvSize: LongInt;
var p1,p2 : ^char;
begin
p1 := EnvStrPtr;
p2 := p1;
{move past environment strings}
repeat
while p2^<>#0 do begin
PtrInc(Pointer(p2),1);
end;
PtrInc(Pointer(p2),1);
until p2^=#0;
if Dos_Version >= 300 then begin {skip program name}
PtrInc(Pointer(p2),3);
while p2^<>#0 do
PtrInc(Pointer(p2),1);
PtrInc(Pointer(p2),1);
end;
EnvSize := PtrDiff(p2,p1)+1;
end;
function MaxEnvSize:LongInt;
begin
MaxEnvSize := MCBPtr(Ptr(Pred(EnvSeg),0))^.PCount shl 4;
end;
procedure UseMyPSP;
begin
PSP := PrefixSeg;
end;
Procedure UseParentPSP;
begin
PSP := WordP(Ptr(PSP,$16))^;
end;
Procedure UseRootPSP;
var oldPSP : word;
begin
repeat
oldPSP := PSP;
UseParentPSP;
until PSP=oldPSP;
end;
{-----------------------------------------------------------------------------}
Type ASCIIz = array [0..255] of char;
ASCIIptr = ^ASCIIz;
function LenZ(var c:ASCIIz): Word; {length of ASCIIz string}
var i: Word;
begin
for i := 0 to MaxInt do
if c[i]=#0 then begin
LenZ := i;
exit;
end;
LenZ := MaxInt;
end;
function StrZn(var c:ASCIIz;MaxLen:integer):string;
label done;
var i,j: integer;
begin
MaxLen := MaxLen-1;
for i := 0 to MaxLen do begin
if c[i]=#0 then goto done;
StrZn[i+1] := c[i];
end;
i := MaxLen+1;
done: StrZn[0] := chr(i);
end;
function StrZ(var c:ASCIIz):string;
const MaxLen = 254;
label done;
var i,j: integer;
begin
for i := 0 to MaxLen do begin
if c[i]=#0 then goto done;
StrZ[i+1] := c[i];
end;
i := MaxLen+1;
done: StrZ[0] := chr(i);
end;
function ToDelim(d:string; var s:string):integer;
var i:integer;
begin
i := pos(d,s); {length to first delimiter}
if i>0 then
s[0] := chr(i-1)
else
i := length(s);
ToDelim := i;
end;
{----------------------------------------------------------------------------}
function ParamString: String;
type StrPtr = ^String;
begin
ParamString := StrPtr(Ptr(PrefixSeg,$80))^;
end;
{----------------------------------------------------------------------------}
var EnvPtr : ASCIIptr;
function FirstEnv:String;
var s: string[255];
i: integer;
begin
EnvPtr := EnvStrPtr;
FirstEnv := NextEnv;
end;
function NextEnv:String;
var s: string;
i: integer;
begin
if EOEnv then
NextEnv := ''
else begin
s := StrZ(EnvPtr^);
i := ToDelim(#0,s);
PtrInc(Pointer(EnvPtr),i+1);
NextEnv := s;
end;
end;
procedure SkipEnv;
var i : integer;
begin
for i := 1 to MaxInt do
if EnvPtr^[i]=#0 then begin
PtrInc(Pointer(EnvPtr),i+1);
exit
end;
end;
function GetEnvPtr(name:string):Pointer;
var i : integer;
begin
for i := 1 to length(name) do name[i] := upcase(name[i]);
name := name + '=';
EnvPtr := EnvStrPtr;
repeat
if strZn(EnvPtr^,length(name)) = name then begin
GetEnvPtr := EnvPtr;
exit;
end;
SkipEnv;
until EoEnv;
GetEnvPtr := EnvPtr;
end;
function EOEnv:Boolean;
begin
EOEnv := (EnvPtr^[0]=#0);
end;
{----------------------------------------------------------------------------}
procedure DelEnv(name:String);
var p1,p2 : ASCIIptr;
begin
p1 := GetEnvPtr(name);
if not EoEnv then begin
SkipEnv;
p2 := EnvPtr;
move(p2^,p1^, EnvSize - PtrDiff(p2,EnvStrPtr));
end;
end;
function SetEnv(name,env:String):boolean;
var p1 : ASCIIptr;
l : LongInt;
begin
DosError := 0;
{Null strings remove the variable from the environment}
if env='' then begin
DelEnv(name);
SetEnv := True;
exit;
end;
SetEnv := FALSE;
{Make sure env isn't too big}
p1 := GetEnvPtr(name); {null string if not found}
l := LenZ(p1^);
if l=0 then l := -1; {trick to add 1 to the new length}
if MaxEnvSize < length(name)+1+length(env) + EnvSize - l then begin
DosError := 8; {Not Enough Memory}
exit;
end;
DelEnv(name);
{insert new string}
env := UpperStr(name)+'='+env;
{go to end of environment}
EnvPtr := EnvStrPtr;
while not EoEnv do SkipEnv;
{make room}
p1 := EnvPtr; PtrInc(Pointer(p1),length(env)+1);
move(EnvPtr^,p1^,EnvSize-PtrDiff(EnvPtr,EnvStrPtr)-1);
{move in data}
move(env[1],EnvPtr^,length(env));
ASCIIptr(EnvPtr)^[length(env)] := #0;
SetEnv := TRUE;
end;
function SetPath(path:String):boolean;
begin
SetPath := SetEnv('PATH',UpperStr(path));
end;
{----------------------------------------------------------------------------}
var namePtr : ASCIIptr;
dummy : LongInt;
namedDelim : string;
function EONamed:Boolean;
begin
EONamed := (namePtr^[0]=#0);
end;
function FirstNamed(name,delim:String):string;
var
s: string;
i: integer;
begin
namePtr := GetEnvPtr(name);
namedDelim := delim;
if EoEnv then begin
FirstNamed := '';
exit;
end;
PtrInc(Pointer(namePtr),length(name)+1); {skip past the name}
s := StrZ(namePtr^);
i := ToDelim(delim,s);
FirstNamed := s;
PtrInc(Pointer(namePtr),length(s)+1);
end;
function NextNamed:string;
var
s: string;
i: integer;
begin
if EONamed then begin
NextNamed := '';
end
else begin
s := StrZ(namePtr^);
i := ToDelim(NamedDelim,s);
PtrInc(Pointer(namePtr),i);
NextNamed := s;
end;
end;
{-----------------------------------------------------------------------------}
var FileInfo : SearchRec;
function ContainsWildcards(filename:string):boolean;
begin
ContainsWildcards := ((pos('?',filename)>0) or (pos('*',filename)>0))
end;
function FileExists(name:string):Boolean;
begin
if (not AllowWildcards) and ContainsWildcards(name) then begin
FileExists := FALSE;
exit;
end;
FindFirst(Name,0,FileInfo);
FileExists := (DosError=0);
end;
{-----------------------------------------------------------------------------}
{----------------------------------------------------------------------------}
function DirDelim(s:String):String;
var i: integer;
c: char;
begin
DirDelim := '';
i := length(s);
while (i>0) and (s[i]=' ') do i := pred(i);
if i<=0 then exit;
s[0] := chr(i);
if (i<1) or not (s[i] IN [':','\']) then
s := s + '\';
DirDelim := s;
end;
function FirstPath: String;
begin
FirstPath := DirDelim(FirstNamed('PATH',';'));
end;
function NextPath: String;
begin
NextPath := DirDelim(NextNamed);
end;
function SpecifiesDrive(var filename:string):boolean;
begin
SpecifiesDrive := (filename[2]=':') and (length(filename)>1)
end;
function PathTo(filename:string):string;
var path: string;
found: boolean;
procedure CurrentPath;
begin
if FileExists(path+filename) then begin {Check Current Directory}
if (filename[1]='\') then begin {root directory}
found := TRUE;
end
else begin
if SpecifiesDrive(path) then
GetDir(ord('A')-ord(upcase(path[1]))+1,path)
else
GetDir(0,path);
found := FileExists(path+filename);
end;
path := DirDelim(path);
end;
end;
begin
found := FALSE;
if filename<>'' then begin
if SpecifiesDrive(filename) then begin
path := Copy(filename,1,2);
filename := Copy(filename,3,SizeOf(FileName));
CurrentPath; {Check the Named Disk Drive}
end;
if not found then begin
path := '';
CurrentPath; {Check the Default Path}
end;
if (not found) and (Copy(filename,1,1)<>'\') then begin
path := FirstPath; {Check the Path}
found := FileExists(path+filename);
while not (EONamed or found) do begin
path := NextPath;
found := FileExists(path+filename);
end;
end;
if not found then begin {Check the Program's Directory}
found := FileExists(MyDir+filename);
if found then path := MyDir;
end;
if found then
PathTo := path
else
PathTo := '';
end;
end;
function FFind(filename:string):string;
var p : string;
d : DirStr;
n : NameStr;
x : ExtStr;
begin
p := PathTo(filename);
if p<>'' then
if SpecifiesDrive(filename) then
FFind := FExpand(p+copy(filename,3,255))
else
FFind := FExpand(p+filename)
else if FileExists(filename) then
FFind := FExpand(filename)
else
FFind := FFindErr;
end;
function DOS_Version: integer;
{Returns the version of DOS being used}
var r : registers;
begin
r.ax := $3000;
MsDos(r);
with r do
DOS_Version := al * 100 + ah
end;
{-----------------------------------------------------------------------------}
var
pPath : string;
pDir : DirStr;
pName : NameStr;
pExt : ExtStr;
procedure GetPName;
var
c : ^char;
i : word;
begin
if DOS_Version<300 then begin {Only for DOS 3.x and greater}
pPath := '';
pName := '';
end
else begin
c := EnvStrPtr;
{Skip to the end of the Environment}
repeat
while c^<>#0 do
PtrInc(pointer(c),1);
PtrInc(pointer(c),1);
until c^=#0;
PtrInc(Pointer(c),3);
pPath := FExpand(StrZ(AsciiPtr(c)^));
FSplit(pPath,pDir,pName,pExt);
end;
end;
function ProgPath: PathStr; {Path to program owning current PSP}
begin
GetPName; ProgPath := pPath;
end;
function ProgDir: DirStr; {Directory of program owning current PSP}
begin
GetPName; ProgDir := pDir;
end;
function ProgName: NameStr; {Name of program owning current PSP}
begin
GetPName; ProgName := pName;
end;
function ProgExt: ExtStr; {Extension of program owning current PSP}
begin
GetPName; ProgExt := pExt;
end;
{-----------------------------------------------------------------------------}
{$IFDEF VER40} {These objects are already in TP Version 5's Dos Unit}
function DosVersion: word; { lo = version (ex. 3); hi = fraction (ex. .2) }
var r : registers;
begin
r.ax := $3000;
MsDos(r);
DOSVersion := r.ax;
end;
function EnvCount: integer; {number of Environment Strings}
var i: integer;
begin
UseMyPSP;
EnvPtr := EnvStrPtr;
i := 0;
while not EoEnv do begin
SkipEnv;
i := succ(i);
end;
EnvCount := i;
end;
function EnvStr(Index:integer): string; {get Env. String number index}
begin
UseMyPSP;
EnvPtr := EnvStrPtr;
while (index>1) and not EoEnv do begin
SkipEnv;
index := pred(index);
end;
if index = 1 then
EnvStr := NextEnv
else
EnvStr := '';
end;
function GetEnv(EnvVar:string): string; {get Env. String named by EnvVar}
begin
GetEnv := FirstNamed(EnvVar,#0);
end;
function FExpand(Path:PathStr):PathStr;
var
i : integer;
old: PathStr;
begin
FSplit(path,pDir,pName,pExt);
if length(pDir)=0 then
GetDir(0,pDir)
else begin
if pDir[length(pDir)]='\' then pDir[0] := chr(length(pDir)-1);
GetDir(0,old);
ChDir(pDir);
GetDir(0,pDir);
ChDir(old);
end;
path := pName+pExt;
for i := 1 to length(path) do path[i] := UpCase(path[i]);
FExpand := pDir+'\'+path;
end;
function FSearch(Path:PathStr;DirList:string):PathStr;
var dir: string;
i: integer;
found: boolean;
procedure NextDir;
var j : integer;
begin
i := succ(i); j := i;
while (j<length(DirList)) and (DirList[j]<>';') do j := succ(j);
Dir := DirDelim(Copy(Dirlist,i,j-i))+Path;
i := j;
end;
begin
FSearch := '';
if Path<>'' then begin
found := FileExists(path); {Check Current Directory}
if Found then
Dir := Path
else begin {Check DirList}
i := 0;
repeat
NextDir;
found := FileExists(Dir);
until (i>=length(DirList)) or found;
end;
if found then
FSearch := Dir;
end;
end;
procedure FSplit(Path:PathStr; var Dir:DirStr; var Name:NameStr; var Ext:ExtStr);
var i,j : integer;
done : boolean;
begin
Dir := ''; Name := ''; Ext := '';
if Path='' then exit;
if Path[length(Path)]='.' then begin
Dir := Path;
if length(Path)=1 then exit;
if Path[length(Path)-1] in ['.','\'] then exit;
Dir := '';
end;
i := length(Path); j := 0; done := FALSE;
while (i>0) and (j<sizeof(Ext)) and not done do begin
done := (Path[i]='.');
if done then
Ext := Copy(Path,i,j+1);
j := succ(j);
i := pred(i);
end;
i := length(Path) - length(Ext); j := i;
while (i>0) and not (Path[i] in [':','\']) do i := pred(i);
Name := Copy(Path,i+1,j-i);
Dir := Copy(Path,1,i);
end;
{$ENDIF}
{-----------------------------------------------------------------------------}
begin
UseMyPSP;
EnvPtr := EnvStrPtr;
dummy := 0;
namePtr := @dummy;
GetPName;
MyPath := pPath;
MyDir := pDir; MyName := pName; MyExt := pExt;
end.